package com.toe.recommend.webapi.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.toe.commodity.service.CommodityGoodsService;
import com.toe.common.restful.JsonPage;
import com.toe.pojo.entity.commodity.CommodityGoods;
import com.toe.pojo.vo.commodity.GoodsListDetailsVO;
import com.toe.pojo.vo.commodity.RecommendRandomVO;
import com.toe.pojo.vo.recommend.RecommendCommodityVO;
import com.toe.pojo.vo.user.UserHistoryVO;
import com.toe.recommend.service.RecommendCommodityService;
import com.toe.recommend.webapi.mapper.RecommendCommodityMapper;
import com.toe.recommend.webapi.pojo.HistoryKey;
import com.toe.recommend.webapi.pojo.UserRelationshipsKey;
import com.toe.recommend.webapi.util.HashUtil;
import com.toe.recommend.webapi.util.MathUtil;
import com.toe.user.service.UserHistoryService;
import com.toe.user.service.UserUsertblService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 陶涛
 * @since 2022-07-19
 */
@Service
@DubboService
public class RecommendCommodityServiceImpl extends ServiceImpl<RecommendCommodityMapper, CommodityGoods> implements RecommendCommodityService {

    @DubboReference
    UserUsertblService dubboUserService;

    @DubboReference
    UserHistoryService dubboHistoryService;

    @DubboReference
    CommodityGoodsService dubboGoodsService;

    /**
     * 推荐商品
     * @param userId
     * @return
     */
    @Override
    public List<RecommendCommodityVO> recommendCommodity(Long userId, int count) {
        System.out.println("==========userId = "+userId+"==============");
//        int count = 9;
        List<Long> userIds = dubboUserService.listAllUserId();
        List<Long> goodsIds = dubboHistoryService.listGoodsByUserId(userId);
        System.out.println("goodIds.size = "+goodsIds.size());
        goodsIds.forEach(System.out::println);
        List<UserHistoryVO> historyVOS = dubboHistoryService.listHistory();
        UserHistoryVO hasHistory = null;
        for (UserHistoryVO historyVO : historyVOS) {
           if (userId.equals(historyVO.getUserId())) {
               hasHistory = historyVO;
               break;
           }
        }
        if (hasHistory == null) {
            System.out.println("------没有用到算法-------");
            JsonPage<RecommendRandomVO> commodity = dubboGoodsService
                    .getRecommendRandom(1, 100);
            List<RecommendRandomVO> random =
                    MathUtil.random(commodity.getList(), count);
            List<RecommendCommodityVO> list = new ArrayList<>();
            for (RecommendRandomVO goods : random) {
                RecommendCommodityVO commodityVO = new RecommendCommodityVO();
                System.out.println("源 -> " + goods);
                BeanUtils.copyProperties(goods, commodityVO);
                System.out.println("输出 -> " + commodityVO);
                list.add(commodityVO);
            }
            return list;
        }

        Map<HistoryKey, Long> historyMap = new HashMap<>();

        for (Long user : userIds) {
            for (Long goodsId : goodsIds) {
                System.out.println("开始输出");
                HistoryKey key = new HistoryKey(user, goodsId);
                historyMap.put(key, 0L);
                System.out.println("-------------输出key: "+key);
            }
        }

        for (UserHistoryVO history : historyVOS) {
            System.out.println("history = "+history.toString());
            HistoryKey key = new HistoryKey(history.getUserId(), history.getGoodsId());
            System.out.println("=========是否含有key: "+historyMap.containsKey(key));
            if (historyMap.containsKey(key)) {
                Long replace = historyMap.replace(key, historyMap.get(key) + 1);
            } else {
                historyMap.put(key, 1L);
            }
        }
        System.out.println("==========完成了!==========");
        historyMap.entrySet().forEach(System.out::println);

        Map<UserRelationshipsKey, Double> sim = new HashMap<>();
        double numerator = 0D;
        double denominatorUser1 = 0D;
        double denominatorUser2 = 0D;
        for (Long user : userIds) {
            for (Long goodsId : goodsIds) {
                if (user.equals(userId)) break;

                HistoryKey myKey = new HistoryKey(userId, goodsId);
                HistoryKey key = new HistoryKey(user, goodsId);
                numerator += historyMap.get(myKey) * historyMap.get(key);
                denominatorUser1 += historyMap.get(myKey) * historyMap.get(myKey);
                denominatorUser2 += historyMap.get(key) * historyMap.get(key);
            }

            if (user.equals(userId)) continue;
            System.out.println("numerator: "+numerator+"   denominator: "
                    +Math.sqrt(denominatorUser1*denominatorUser2));
            double value = numerator / Math.sqrt(denominatorUser1*denominatorUser2);
            UserRelationshipsKey key = new UserRelationshipsKey(userId, user);
            sim.put(key, value);
        }

        System.out.println("==========sim.value==========");
        sim.entrySet().forEach(System.out::println);
        List<Double> maxValuesSim = HashUtil.getMaxValue(sim, 3);
        List<UserRelationshipsKey> maxKeysSim = HashUtil.getKey(sim, maxValuesSim);

        System.out.println("===============maxSimUserId=============");
        maxKeysSim.forEach(System.out::println);

        List<Long> maxGoodsIds = new ArrayList<>();
        for (UserHistoryVO history : historyVOS) {
            for (UserRelationshipsKey user : maxKeysSim) {
                if (user.getUserId2().equals(history.getUserId())) {
                    maxGoodsIds.add(history.getGoodsId());
                    System.out.println("maxGoodsId = "+history.getGoodsId());
                    break;
                }
            }
        }

        Map<HistoryKey, Double> p = new HashMap<>();
        double numerator1 = 0D;
        double denominator = 0D;
        System.out.println("==========获取商品===========");
        for (Long goodsId : maxGoodsIds) {
            for (UserRelationshipsKey simKey : maxKeysSim) {
                HistoryKey rKey = new HistoryKey(simKey.getUserId2(), goodsId);

                if (!historyMap.containsKey(rKey)) {
                    historyMap.put(rKey, 0L);
                }

                numerator1 += sim.get(simKey) * historyMap.get(rKey);
                denominator += sim.get(simKey);
            }
            double value = numerator1 / denominator;
            HistoryKey pKey = new HistoryKey(userId, goodsId);
            p.put(pKey, value);
        }

        List<Double> maxValueP = HashUtil.getMaxValue(p, 50);
        List<HistoryKey> maxKeysP = HashUtil.getKey(p, maxValueP);
        List<Long> ids = new ArrayList<>();
        for (HistoryKey key : maxKeysP) {
            ids.add(key.getGoodsId());
        }

        System.out.println("============ids============");
        ids.forEach(System.out::println);
        System.out.println("=============进入新服务=============");
        List<RecommendCommodityVO> goods = dubboGoodsService.getCommodityGoodsByIds(ids);

        return MathUtil.random(goods, count);
    }

}
